﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DecisionTree
{
    static class Tools
    {
        public static double Entropy(byte[] outputs, int[] idxs, int numOutputClass)
        {
            if (idxs.Length == 0)
                return 0;

            int[] frequencies = new int[numOutputClass];
            double[] p = new double[numOutputClass];

            for (int i = 0; i < idxs.Length; i++)
                frequencies[outputs[idxs[i]]]++;

            for (int i = 0; i < numOutputClass; i++)
                p[i] = (double)frequencies[i] / idxs.Length;

            double sum = 0;
            for (int i = 0; i < p.Length; i++)
                if (p[i] != 0) sum += p[i] * Math.Log(p[i], 2);

            return -1 * sum;
        }

        public static int[] CreateIndexes(int numIndex)
        {
            int[] rVal = new int[numIndex];

            for (int i = 0; i < numIndex; i++)
                rVal[i] = i;

            return rVal;
        }

        public static int MostCommon(byte[] outputs, int[] idxs, int numOutputClass)
        {
            int[] frequencies = new int[numOutputClass];

            for (int i = 0; i < idxs.Length; i++)
                frequencies[outputs[idxs[i]]]++;

            return frequencies.MaxIndex();
        }

        public static double[] GetHistogram(byte[] outputs, int[] idxs, int numOutputClass, int level)
        {
            double[] frequencies = new double[numOutputClass];
            double sum = 0;

            for (int i = 0; i < idxs.Length; i++)
                frequencies[outputs[idxs[i]]]++;

            for (int i = 0; i < frequencies.Length; i++)
                sum += frequencies[i];

            for (int i = 0; i < frequencies.Length; i++)
                frequencies[i] /= sum;

            for (int i = 0; i < frequencies.Length; i++)
                frequencies[i] /= (level + 1);

            return frequencies;
        }

        /// <summary>
        ///   Computes the split information measure.
        /// </summary>
        /// 
        /// <param name="numTotalRecords">The total number of samples.</param>
        /// <param name="partitions">The partitioning.</param>
        /// <returns>The split information for the given partitions.</returns>
        public static double SplitInformation(int numTotalRecords, int[][] partitions)
        {
            double info = 0;

            for (int i = 0; i < partitions.Length; i++)
            {
                double p = (double)partitions[i].Length / numTotalRecords;
                if (p != 0)
                    info -= p * Math.Log(p, 2);
            }

            return info;
        }
    }
}
